/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
 H       ALU.h
 H       Application name: Arithmetic Logic Unit Simulator Header File
 H       Programmers names: Tony Butterfield, Evan Phillips
 H       Date completed: 2/14/11
 H       Brief Description: This is the header file that defines an ADT for the ALU and also contains
 H		the previously defined Register and RegisterFile ADT's.
 H
 HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/

#ifndef BOOLEAN
#define BOOLEAN unsigned char
#define TRUE 1
#define FALSE 0
#endif
 

//The below are needed to avoid multiple file compilation
/***************************************************************************************************
 * ADT: Register 16
 * Description: A register is a 16 bit variable type implemented as an unsigned short.
 ***************************************************************************************************/

/*#################################################################################################
 # Defines
 ##################################################################################################*/
#define uchar 				unsigned char
#define ushort 				unsigned short
#define LOB_MASK 			0x00FF
#define HOB_MASK 			0xFF00
#define BIT_15 				0x8000
#define NULL_ERR 			0x2

/*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
 $ Typedefs
 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/
typedef ushort Register;
typedef Register * RegisterPtr; 

/*-------------------------------------------------------------------------------------------------
 - Prototypes
 - Basic operations
 -      Initialize: creates register object and puts a random value from 0 to 65535 into it.
 -      GetLowByte: returns an unsigned char (uchar) from LOB of register
 -      GetHIByte:  returns a uchar from the HOB of register
 -      PutLowByte: puts a uchar into the LOB of the register
 -      PutHIByte:  puts a uchar into the HOB of the register
 -      SignOf:     returns bit 15 value in a uchar
 -      Destructor: not needed
 - Composite Operations
 -      GetRegValue: returns a ushort, the value in the register
 -      PutRegValue: returns error, puts ushort into register
 ---------------------------------------------------------------------------------------------------*/
RegisterPtr register_initialize(void); //allocates space and returns pointer
uchar register_getLowByte(RegisterPtr, int *); //returns LOB if successful
uchar register_getHiByte(RegisterPtr, int *); //returns HOB if successful
int register_putLowByte(RegisterPtr, uchar); //returns error code
int register_putHiByte(RegisterPtr, uchar); //returns error code
uchar register_signOf(RegisterPtr); //returns 0, 1, 2 or greater error code
ushort register_getRegValue(RegisterPtr, int *);
int register_putRegValue(RegisterPtr, ushort);




/***************************************************************************************************
 * ADT: SC-2 Register File (uses Register)
 * Description: The register file is a set of sixteen 16-bit registers as described in the SC-2 document
 ***************************************************************************************************/

/*#################################################################################################
 # Defines
 ##################################################################################################*/
#define REGISTER_COUNT 16
#define R0 (uchar) 0
#define R1 (uchar) 1
#define R2 (uchar) 2
#define R3 (uchar) 3
#define R4 (uchar) 4
#define R5 (uchar) 5
#define R6 (uchar) 6
#define R7 (uchar) 7
#define R8 (uchar) 8
#define R9 (uchar) 9
#define RA (uchar) 0xA
#define RB (uchar) 0xB
#define RC (uchar) 0xC
#define RD (uchar) 0xD
#define RE (uchar) 0xE
#define RF (uchar) 0xF
#define LOB_WHICH 0
#define HOB_WHICH 1
#define REG_NOT_FOUND_ERR 0x3

/*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
 $ Typedefs
 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/
//      typedef RegisterPtr (*RegisterFilePtr)[REGISTER_COUNT]; //to be allocated as an array
typedef RegisterPtr * RegisterFilePtr;

/*-------------------------------------------------------------------------------------------------
 - Prototypes
 - Basic Operations
 -      Initialize: creates a register file of 16 Register objects in an array
 -      GetByteFrom: returns a uchar from a designated register and LOB or HOB
 -      PutByteTo:   puts a single byte to either LOB or HOB or register
 -      Destructor: not needed
 -      Composite Operations
 -      GetWordFrom: returns a ushort, the content of the designated register
 -      PutWordTo: puts the ushort into the designated register
 --------------------------------------------------------------------------------------------------*/
RegisterFilePtr registerFile_initialize(); //allocates space for 16 register pointers and calls register_initialize for each slot
uchar registerFile_getByteFrom(RegisterFilePtr, uchar, uchar, int *); //returns the byte in register reg_num and HOB or LOB indicated 
                                                                      //by which, sets error code
int registerFile_putByteTo(RegisterFilePtr, uchar, uchar, uchar); //puts the byte into the reg_num and HOB or LOB indicated by which
                                                                  //returns error code
ushort registerFile_getRegValue(RegisterFilePtr, uchar, int *); //returns the register content; sets error code
int registerFile_putRegValue(RegisterFilePtr, uchar, ushort); //puts the value into the designated reg_num register; returns error code




/***************************************************************************************************
 * ADT: ALU
 * Description: ALU simulation for the SC-2 (uses 'Register16' and 'SC-2 RegisterFile')
 ***************************************************************************************************/
 
/*#################################################################################################
 # Defines
 ##################################################################################################*/

// op_sel values for ALU operations
#define OP_ADD		0x00
#define OP_SUB		0x01	
#define OP_MUL		0x02
#define OP_DIV		0x03
#define OP_NEG		0x04
#define OP_AND		0x05
#define OP_OR		0x06
#define OP_XOR		0x07
#define OP_NOT		0x08
#define OP_SHL		0x09
#define OP_SHR		0x0A


// values of the status bits within the SW register.	
#define SW_CLEAR_STATUS	0x0FFF
#define SW_N_BIT	0x8000
#define SW_Z_BIT	0x4000
#define SW_C_BIT	0x2000
#define SW_O_BIT	0x1000	 

//more error codes
#define OP_OUT_OF_RANGE_ERR 0x4
#define ALU_DIVIDE_BY_ZERO 0x5

//bit masks
#define REG16_MASK 0xFFFF
#define BIT_15 0x8000
#define HOW_MASK 0xFFFF0000
#define LOW_MASK 0x0000FFFF
//carry detect
#define MAX_USHORT 0xFFFF
#define MAX_SIGNED_SHORT 0x7FFF
#define MIN_SIGNED_SHORT 0x8000

/*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
 $ Typedefs
 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/
 
typedef struct alu_str		 
	{				
		RegisterPtr A;		//	A - input (operand 1)
		RegisterPtr B;		//	B - input (operand 2)
		RegisterPtr C;		//	C - output
		uchar op_sel;		//	operation select
		
	} ALUStr;
	
typedef ALUStr * ALU;


/*-------------------------------------------------------------------------------------------------
 - Prototypes
 - Basic Operations:	
 -		Initialize:  Creates ALU object		
 -		Execute:   Simulates a clock signal, causing the selected operation to execute.
 -
 -	'External' Operations	
 -		Load A:  Simulates the state of the A register as LdA is 
 -				enabled by explicitly loading an operand into A
 -				
 -		Load B:  Simulates the state of the B register as LdB is 
 -				enabled by explicitly loading an operand into B
 -				
 -		Select Operation:  Simulates the op_sel signal by loading a 
 -				value into the op_sel register
 -
 -		Set Status:  	Sets the relevant bit in SW
 -				
 -		Read Output C:  Simulates the state of the data bus as DrALU is
 -				enabled by explicitly reading the value of C				
 -
 -	'Internal' Operations:	
 -		Addition:  	C <- A + B, set status		
 -		Subtraction:  	C <- A - B, set status		
 -		Multiplication: $R8 <- (low-order) A * B, set status		
 -				$R9 <- (high-order) A * B, set status				
 -		Division: 	$RA <- (quotient) A / B, set status	
 -				$RB <- (remainder) A / B, set status				
 -		Negation:  	C <- ~A + 1 (2's complement), set status		
 -		AND:		C <- A & B, set status		
 -		OR:		C <- A | B, set status		
 -		XOR:		C <- A ^ B (bitwise XOR), set status		
 -		NOT:		C <- ~A, set status		
 -		Shift Left:	C <- A * 2, set status		
 -		Shift Right: 	C <- A / 2, set status		
 -		
 - 
 --------------------------------------------------------------------------------------------------*/
ALU	ALU_initialize();					// allocate ALU
int	ALU_execute(ALU, RegisterFilePtr, RegisterPtr);		// execute the selected operation on A&B
int	ALU_loadA(ALU, ushort);					// load ALU reg A with value
int 	ALU_loadB(ALU, ushort);					// load ALU reg B with value
int 	ALU_selectOperation(ALU, uchar);			// select operation to be performed
int	ALU_setStatusWord(ALU, RegisterFilePtr, RegisterPtr);	// update NZCO bits of SW. 
ushort	ALU_readC(ALU, int*);					// return value in ALU reg C
int	ALU_add(ALU);						// C <- A + B
int 	ALU_subtract(ALU);					// C <- A - B
int 	ALU_multiply(ALU, RegisterFilePtr);			// needs address of regfile $R8 <- (low-order) A * B	
								// 			    $R9 <- (high-order) A * B
int	ALU_divide(ALU, RegisterFilePtr);			// needs address of regfile $RA <- (quotient) A / B
								// 			    $RB <- (remainder) A / B
int	ALU_negate(ALU);					// C <- ~A + 1 (2's complement)
int 	ALU_and(ALU);						// C <- A & B
int 	ALU_or(ALU);						// C <- A | B
int 	ALU_xor(ALU);						// C <- A ^ B
int 	ALU_not(ALU);						// C <- ~A
int 	ALU_shiftLeft(ALU);					// C <- A * 2
int 	ALU_shiftRight(ALU);					// C <- A / 2


// TEST DRIVER PROTOTYPES
uchar test_getOpSel(ALU, int*);
int display_registerFile(RegisterFilePtr);

